home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 426-450 / disk_445 / optmouse / optmouse.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  8KB  |  345 lines

  1. /*
  2.  * OptMouse.c
  3.  *
  4.  * Serial Port Optical Mouse Driver
  5.  *
  6.  * (c) Copyright 1989 J. Edward Hanway
  7.  * This code may be freely redistributed for non-commercial purposes. There
  8.  * is NO WARRANTY on this program. The author assumes no responsibility for
  9.  * any damages resulting from use of this program. You know the drill.
  10.  *
  11.  * Language: Lattice C 5.02
  12.  *
  13.  * Revision History:
  14.  *
  15.  * Version 1.0    27 May 1989
  16.  *    Supports Mouse Systems M2/M3 serial optical mouse
  17.  * Version 1.1  3 June 1989
  18.  *    Added support for other device/unit combinations besides serial.device
  19.  *    (e.g. siosbx.device) *** NOTE: This feature has not been tested. ***
  20.  */
  21.  
  22. #define VERSION "1.1"
  23.  
  24. #include <exec/types.h>
  25. #include <devices/serial.h>
  26. #include <devices/input.h>
  27. #include <devices/inputevent.h>
  28. #include <devices/keyboard.h>
  29. #include <libraries/dos.h>
  30. #include <proto/exec.h>
  31. #include <proto/dos.h>
  32. #include <string.h>
  33. #include <stdlib.h>
  34.  
  35. #define SAY(x) \
  36. {if(_Backstdout) {Write(_Backstdout, (x), strlen(x)); Close(_Backstdout);}}
  37.  
  38. void MemCleanup() {}
  39.  
  40. /* This stuff is for linking with cback.o (for "load and stay resident" code) */
  41.  
  42. LONG    _stack = 4000;        /* stack size */
  43. char    *_procname = "OptMouse";/* process name */
  44. LONG    _priority = 20;        /* priority */
  45. LONG    _BackGroundIO = 1;    /* requires I/O */
  46. extern BPTR _Backstdout;
  47.  
  48. static char        *ser_portname = "OptMouse";
  49.     
  50. /* default device/unit */
  51. static char        *device = SERIALNAME;
  52. static int        unit = 0;
  53.  
  54.  
  55. static struct dev {
  56.     struct MsgPort        *port;
  57.     struct IORequest    *iob;
  58.     BOOL            open;
  59. }    ser = {NULL, NULL, FALSE},
  60.     in = {NULL, NULL, FALSE},
  61.     time = {NULL, NULL, FALSE},
  62.     key = {NULL, NULL, FALSE};
  63.     
  64. /* shorthand */
  65. #define SER_IOB        ((struct IOExtSer *)(ser.iob))
  66. #define IN_IOB        ((struct IOStdReq *)(in.iob))
  67. #define TIME_IOB    ((struct timerequest *)(time.iob))
  68. #define KEY_IOB        ((struct IOStdReq *)(key.iob))
  69.  
  70. static signed char    b;            /* byte read from mouse */
  71.  
  72. static struct button {
  73.     BOOL left, middle, right;
  74. }    button, last_button = { FALSE, FALSE, FALSE };
  75.  
  76. static struct InputEvent event = {
  77.     NULL,                /* NextEvent */
  78.     IECLASS_RAWMOUSE,        /* Class */
  79.     NULL,                /* SubClass */
  80.     NULL,                /* Code, filled in later */
  81.     NULL,                /* Qualifier, filled in later */
  82.     { NULL, NULL },            /* Position, filled in later */
  83.     { 0L, 0L }            /* TimeStamp */    
  84. };
  85.  
  86. /* Matrix for reading key states. All we care about are the 
  87.  * shift/ctrl/alt/amiga keys, which are conveniently qrouped in
  88.  * keymatrix[12] in the same order as required for the qualifier
  89.  *
  90.  * The following number, which is the ONLY read length that works for
  91.  * KBD_READMATRIX, was documented NOWHERE! I had to find it by trial and error.
  92.  */
  93. #define GODDAMN_KEY_MATRIX_READ_LENGTH    13
  94.  
  95. static UBYTE keymatrix[16];
  96.  
  97. void close_dev(struct dev *dev)
  98. {
  99.     if(dev->open) {
  100.         AbortIO(dev->iob);
  101.         CloseDevice(dev->iob);
  102.         dev->open = FALSE;
  103.     }
  104.     if(dev->iob) {
  105.         DeleteExtIO(dev->iob);
  106.         dev->iob = NULL;
  107.     }
  108.     if(dev->port) {
  109.         DeletePort(dev->port);
  110.         dev->port = NULL;
  111.     }
  112. }
  113.  
  114. void die(void)
  115. {
  116.     close_dev(&time);
  117.     close_dev(&in);
  118.     close_dev(&ser);
  119.     close_dev(&key);
  120.     _exit(0);
  121. }
  122.  
  123. void open_dev(struct dev *dev, char *portname, char *devname, int unit, int size)
  124.     if(!(dev->port = CreatePort(portname, 0)) ||
  125.        !(dev->iob = CreateExtIO(dev->port, size)) ||
  126.        !(dev->open = !OpenDevice(devname, unit, dev->iob, 0L))) {
  127.         SAY("Device error\n");
  128.         die();
  129.     }
  130. }
  131.  
  132. /* my_DoIO does everything that DoIO does (I hope) except it allows for a break
  133.  * signal.
  134.  */
  135. void my_DoIO(struct IORequest *iob)
  136. {
  137.     register LONGBITS signals, sigbit;
  138.  
  139. /* Lattice 5.02 doesn't seem to provide a register-parameter entry to BeginIO,
  140.  * so here's a hack that avoids an annoying 3 line assembly language program.
  141.  * Just don't try to call BeginIO on anything but iob->io_Device.
  142.  */
  143. #pragma libcall iob->io_Device BeginIO 1e 901
  144.  
  145.     iob->io_Flags |= IOF_QUICK;
  146.     BeginIO(iob);
  147.     if(!(iob->io_Flags & IOF_QUICK)) {
  148.         signals = Wait((sigbit = (1L << 
  149.                 iob->io_Message.mn_ReplyPort->mp_SigBit)) |
  150.                    SIGBREAKF_CTRL_C);
  151.         if(signals & sigbit)
  152.             GetMsg(iob->io_Message.mn_ReplyPort);
  153.         if(signals & SIGBREAKF_CTRL_C)
  154.             die();
  155.     }
  156. }
  157.  
  158. #undef isspace
  159.  
  160. int isspace(register char c)
  161. {
  162.     return ((c == ' ') || (c == '\t') || (c == '\n') || (c == '\r'));
  163. }
  164.  
  165. char *skiparg(register char *s)
  166. {
  167.     while(*s && !isspace(*s))
  168.         s++;
  169.     return s;
  170. }
  171.  
  172. char *skipwhite(register char *s)
  173. {
  174.     while(*s && isspace(*s))
  175.         s++;
  176.     return s;
  177. }
  178.  
  179. void _tinymain(char *s)
  180. {
  181.     UWORD        state = 0;
  182.     WORD        dx, dy;
  183.     BOOL        mid_is_shift = 0;
  184.     BOOL        kill = 0;
  185.  
  186.     /* I'm playing it fast and loose with parsing here */
  187.     s = skiparg(s);
  188.     s = skipwhite(s);
  189.     while(*s == '-') {
  190.         switch(*(s+1)) {
  191.             case 'k':
  192.             case 'K':
  193.             kill++;
  194.             break;
  195.             case 'm':
  196.             case 'M':
  197.             mid_is_shift++;
  198.             break;
  199.         }
  200.         s = skiparg(s);
  201.         s = skipwhite(s);
  202.     }
  203.  
  204.     /* device name */
  205.     if(*s) {
  206.         device = s;
  207.         s = skiparg(s);
  208.         if(*s) *s++ = '\0';
  209.         s = skipwhite(s);
  210.     }
  211.  
  212.     /* unit */
  213.     if(*s) {
  214.         (void) stcd_i(s, &unit);
  215.     }
  216.  
  217.     if(FindPort(ser_portname)) {
  218.         if(kill) {
  219.             Signal(FindTask(_procname),SIGBREAKF_CTRL_C);
  220.             SAY("Killed\n");
  221.         } else
  222.             SAY("Already installed\n");
  223.         die();
  224.     }
  225.  
  226.     open_dev(&ser, ser_portname, device, unit, sizeof(struct IOExtSer));
  227.     open_dev(&in, NULL, "input.device", 0L, sizeof(struct IOStdReq));
  228.     open_dev(&time, NULL, TIMERNAME, UNIT_MICROHZ, sizeof(struct timerequest));
  229.     open_dev(&key, NULL, "keyboard.device", 0L, sizeof(struct IOStdReq));
  230.  
  231.     SAY("OptMouse " VERSION " \xA9 Copyright 1989 J. Edward Hanway\n");
  232.  
  233.     /* Set serial port parameters:
  234.      * 1200 baud, 8 bits, no parity, 1 stop bit, no flow control
  235.      */
  236.     SER_IOB->IOSer.io_Command = SDCMD_SETPARAMS;
  237.     SER_IOB->io_Baud = 1200;
  238.     SER_IOB->io_ReadLen = 8;
  239.     SER_IOB->io_StopBits = 1;
  240.     SER_IOB->io_SerFlags = SERF_XDISABLED | SERF_RAD_BOOGIE;
  241.     my_DoIO(ser.iob);
  242.  
  243.     /* Since each IORequest will be used for only one type of command,
  244.      * lots of invariant fields can be filled in here
  245.      */
  246.     KEY_IOB->io_Command = KBD_READMATRIX;
  247.     KEY_IOB->io_Data = (APTR) keymatrix;
  248.     KEY_IOB->io_Length = GODDAMN_KEY_MATRIX_READ_LENGTH;
  249.  
  250.     TIME_IOB->tr_node.io_Command = TR_GETSYSTIME;
  251.  
  252.     IN_IOB->io_Command = IND_WRITEEVENT;
  253.     IN_IOB->io_Flags = 0;
  254.     IN_IOB->io_Length = sizeof(struct InputEvent);
  255.     IN_IOB->io_Data = (APTR) &event;
  256.  
  257.     SER_IOB->IOSer.io_Command = CMD_READ;
  258.     SER_IOB->IOSer.io_Length = 1;
  259.     SER_IOB->IOSer.io_Data = (APTR) &b;
  260.  
  261.     while(TRUE) {
  262.         my_DoIO(ser.iob);
  263.         switch(state) {
  264.             case 0:
  265.             if((b & 0xf8) == 0x80) {
  266.                 button.right  = !(b & (1 << 0));
  267.                 button.middle = !(b & (1 << 1));
  268.                 button.left   = !(b & (1 << 2));
  269.                 state++;
  270.             }
  271.             break;
  272.             case 1:
  273.             dx = b;
  274.             state++;
  275.             break;
  276.             case 2:
  277.             dy = b;
  278.             state++;
  279.             break;
  280.             case 3:
  281.             dx += b;
  282.             state++;
  283.             break;
  284.             case 4:
  285.             dy += b;
  286.  
  287.             /* Now compose the events to be sent to input.device.
  288.              * Currently, 0-4 events (movement, up to 3 button
  289.              * state changes) are sent.
  290.  
  291.             /* Valid time stamp is required for double-clicking
  292.              * to work properly.
  293.              */
  294.             my_DoIO(time.iob);
  295.             event.ie_TimeStamp = TIME_IOB->tr_time;
  296.  
  297.             /* Shift key status is needed for shift-click support */
  298.             my_DoIO(key.iob);
  299.  
  300.             event.ie_X = dx;
  301.             event.ie_Y = -dy;
  302.             event.ie_Code = IECODE_NOBUTTON;
  303.             event.ie_Qualifier = IEQUALIFIER_RELATIVEMOUSE |
  304.             (button.right ? IEQUALIFIER_RBUTTON : 0) |
  305.             ((button.middle && !mid_is_shift) ? IEQUALIFIER_MIDBUTTON : 0) |
  306.             (button.left ? IEQUALIFIER_LEFTBUTTON : 0) | 
  307.             keymatrix[12] |
  308.             ((button.middle && mid_is_shift) ? 
  309.              (IEQUALIFIER_LEFTBUTTON | IEQUALIFIER_LSHIFT) :
  310.              0);
  311.  
  312.             if(dx || dy)
  313.                 my_DoIO(in.iob);
  314.  
  315.             event.ie_X = event.ie_Y = 0;
  316.  
  317.             if(button.left ^ last_button.left) {
  318.                 event.ie_Code = button.left ? IECODE_LBUTTON :
  319.                         IECODE_LBUTTON | IECODE_UP_PREFIX;
  320.                 my_DoIO(in.iob);
  321.             }
  322.  
  323.             if(button.middle ^ last_button.middle) {
  324.                 event.ie_Code = mid_is_shift ? 
  325.                         (button.middle ? IECODE_LBUTTON :
  326.                          IECODE_LBUTTON | IECODE_UP_PREFIX) :
  327.                         (button.middle ? IECODE_MBUTTON : 
  328.                          IECODE_MBUTTON | IECODE_UP_PREFIX);
  329.                 my_DoIO(in.iob);
  330.             }
  331.  
  332.             if(button.right ^ last_button.right) {
  333.                 event.ie_Code = button.right ? IECODE_RBUTTON : 
  334.                         IECODE_RBUTTON | IECODE_UP_PREFIX;
  335.                 my_DoIO(in.iob);
  336.             }
  337.  
  338.             last_button = button;
  339.             state = 0;
  340.             break;
  341.         }
  342.     }
  343. }
  344.